#include "StdAfx.h"


Shader::Shader(ShaderDesc &desc):GameResource(desc)
{
	Scale=Vec3(1,1,1);
}
Shader::~Shader(void)
{
	if(Effect)
		cgDestroyEffect(Effect);
}
void Shader::LoadFromFile()
{
	Scale=Vec3(1,1,1);
	Effect=cgCreateEffectFromFile(globals.Graphics.GetContext(), FileName, NULL);
	ReportError_CG("Failed to load "<<Name<<" effect from "<<FileName);
	Technique=cgGetFirstTechnique(Effect);
	while(Technique)
	{
		if(cgValidateTechnique(Technique))
			return;
		Technique=cgGetNextTechnique(Technique);
	}
	
	_log(Name<<" has no usable techniques!");
}
void Shader::SaveToFile()
{
}
void Shader::UseTechnique(string technique_name)
{
	Technique = cgGetNamedTechnique(Effect, technique_name);
	if(!cgValidateTechnique(Technique))
		_err("Failed to validate:\n"
			"Effect: "<<Name<<"\nTechnique: "<<technique_name);
}
void Shader::BeginPass(string pass_name)
{
	LoadTransforms();
	_err("Failed before beginning a pass");
	Pass=cgGetNamedPass(Technique, pass_name);
	cgSetPassState(Pass);
	_err(Name<<" failed to begin pass");
}
void Shader::EndPass()
{
	cgResetPassState(Pass);
	
	globals.Graphics.InitGLState();
}
CGparameter Shader::GetParam(string param_name)
{
	CGparameter param=cgGetNamedEffectParameter(Effect, param_name);
	if(!param)
		_err(Name<<" effect has no \""<<param_name<<"\" parameter");
	return param;
}
void Shader::SetReal(string param_name, real value)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLSetParameter1f(param, value);
}
void Shader::SetVec2(string param_name, Vec2 value)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLSetParameter2f(param, value.x, value.y);
}
void Shader::SetVec3(string param_name, Vec3 value)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLSetParameter3f(param, value.x, value.y, value.z);
}
void Shader::SetVec4(string param_name, Vec4 value)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLSetParameter4f(param, value.x, value.y, value.z, value.w);
}
void Shader::SetMat44(string param_name, Mat44 value)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLSetMatrixParameterfc(param, value._array);
}
void Shader::LoadTexture(string param_name, sptr<GameResource> texture_resc)
{
	//init the variables
	CGparameter param=GetParam(param_name);
	if(param)
	{
		Texture* texture=_TEXTURE(texture_resc);
		//get texture ID
		GLuint id=0;
		if(texture)
			id=texture->GetID();
		//set the texture parameter
		cgGLSetTextureParameter(param, id);
		_err(Name<<" Effect: failed to load "<<texture_resc->Name<<" into "<<param_name);
	}
}
void Shader::UnloadTexture(string param_name)
{
	CGparameter param=GetParam(param_name);
	if(param)
		cgGLDisableTextureParameter(param);
}
void Shader::LoadWorldViewProj()
{
	CGparameter param=cgGetEffectParameterBySemantic(Effect, "WorldViewProjection");
	if(param)
	{
		Mat44 final_mat, auto_mat;
		
		cgGetMatrixParameterfc(param, auto_mat._array);
		final_mat=_PROJECTION(MainCamera)*_VIEW(MainCamera)*((TranslationMatrix(Translation)*RotationMatrix(Rotation))*ScalingMatrix(Scale));//_WORLDVIEWPROJ(MainCamera,Translation,Rotation, Scale);
		cgGLSetMatrixParameterfc(param,final_mat._array);
	}
}
void Shader::LoadViewProj()
{
	CGparameter param=cgGetEffectParameterBySemantic(Effect, "ViewProjection");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);

	param=cgGetEffectParameterBySemantic(Effect, "ViewProjectionInverse");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_INVERSE);

	param=cgGetEffectParameterBySemantic(Effect, "ViewProjectionTranspose");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_TRANSPOSE);

	param=cgGetEffectParameterBySemantic(Effect, "ViewProjectionInverseTranspose");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
}
void Shader::LoadView()
{
	CGparameter param=cgGetEffectParameterBySemantic(Effect, "View");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);

	param=cgGetEffectParameterBySemantic(Effect, "ViewInverse");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);

	param=cgGetEffectParameterBySemantic(Effect, "ViewTranspose");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_TRANSPOSE);

	param=cgGetEffectParameterBySemantic(Effect, "ViewInverseTranspose");
	if(param)
		cgGLSetStateMatrixParameter(param, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
}
void Shader::LoadWorld()
{
	CGparameter param=cgGetEffectParameterBySemantic(Effect, "World");
	if(param)
	{
		Mat44 mat=(TranslationMatrix(Translation)*RotationMatrix(Rotation))*ScalingMatrix(Scale);//TranslationMatrix(Translation)*RotationMatrix(Rotation)*ScalingMatrix(Scale);
		cgGLSetMatrixParameterfc(param, mat._array);
		param=cgGetEffectParameterBySemantic(Effect, "WorldTranspose");
		if(param)
			cgGLSetMatrixParameterfr(param, mat._array);
		param=cgGetEffectParameterBySemantic(Effect, "WorldInverse");
		if(param)
		{
			mat=ScalingMatrix(Vec3(1.0f/Scale.x, 1.0f/Scale.y, 1.0f/Scale.z))*RotationMatrix(-Rotation)*TranslationMatrix(-Translation);
			cgGLSetMatrixParameterfc(param, mat._array);
			param=cgGetEffectParameterBySemantic(Effect, "WorldInverseTranspose");
			if(param)
			{
				cgGLSetMatrixParameterfr(param, mat._array);
			}			
		}
	}
}
CGeffect Shader::GetEffect()
{
	return Effect;
}
void Shader::LoadLight(sptr<Actor> light_actor)
{
	Light* light=_LIGHT(light_actor);
	if(light)
	{
		SetVec3("LightPos",light->Pos);
		SetVec3("LightColor",light->Color);
		Mat44 LightProj=_WORLDVIEWPROJ(light->GetCamera(), Translation, Rotation, Scale);
		LightProj=BiasMatrix()*LightProj;
		SetMat44("LightProj", LightProj);
	}
}
void Shader::LoadMaterial(sptr<GameResource> mat_resc)
{
	if(mat_resc)
	{
		Material *material=_MATERIAL(mat_resc);
		if(material->DiffuseMap)
			LoadTexture("DiffuseSampler",material->DiffuseMap);
		if(material->NormalMap)
			LoadTexture("NormalSampler",material->NormalMap);
		if(material->SpecularMap)
			LoadTexture("SpecularSampler",material->SpecularMap);
		Vec4 specular=Vec4(material->SpecularColor.x, material->SpecularColor.y, material->SpecularColor.z, material->Shininess);
		SetVec4("Specular", specular);
	}
}
void Shader::LoadTransforms()
{
	if(MainCamera)
	{
		SetVec3("EyePos", MainCamera->GetPos());
		LoadWorldViewProj();
		LoadViewProj();
		LoadView();
	}
	LoadWorld();
	LoadLight(LightActor);
	Mat44 w1=TranslationMatrix(Vec3(100,20,30))*ScalingMatrix(Vec3(10,100,1))*RotationMatrix(Rotator(30,40,50));
	Mat44 w2=TranslationMatrix(Vec3(100,20,30))*RotationMatrix(Rotator(30,40,50))*ScalingMatrix(Vec3(10,100,1));
	w1=w2;
	/*Mat44 view, viewProj, proj, stateView, stateViewProj, stateViewInverse, stateProj;
	CGparameter param=cgGetEffectParameterBySemantic(Effect, "ViewProjection");
	cgGetMatrixParameterfc(param, stateViewProj._array);
	param=cgGetEffectParameterBySemantic(Effect, "View");
	cgGetMatrixParameterfc(param, stateView._array);
	param=cgGetEffectParameterBySemantic(Effect, "ViewInverse");
	cgGetMatrixParameterfc(param, stateViewInverse._array);
	stateProj=stateViewProj*stateViewInverse;
	//final_mat=_WORLDVIEWPROJ(camera,pos,rot);
	viewProj=_PROJECTION(camera)*_VIEW(camera);//*(RotationMatrix(rot)*TranslationMatrix(pos))));
	proj=_PROJECTION(camera);
	view=_VIEW(camera);
	view=viewProj;*/
}
